/**
 TF3J.h
 
 \file
 Declaration of class TF3J.
 
 \author Thomas Burton 
 \date 2/28/12
 \copyright 2012 BNL. All rights reserved.
 */

#ifndef _TF3J_H_
#define _TF3J_H_

#include <TF3.h>
#include <Math/ParamFunctor.h>

/**
 Whenever the input parameters to a ROOT function are changed, the cached
 integral is deleted (as the function has changed).
 For our uses, Q2 and parton depolarisation factor are input parameters that
 change with every event, so it is very inefficient to recompute the integral
 each time.
 This is a special TF3 that caches integrals for bins in Q2 and depolarisation
 factor bins so that they don't have to be recomputed when the function
 parameters change.
 The GetRandom3() method is reimplemented to compute the random values from
 these cached integrals instead of the normal TF3 integral cache.
 */
class TF3J : public TF3 {
   
public:

   TF3J(const char *name,
        Double_t (*fcn)(Double_t*, Double_t*),
        Double_t xmin,
        Double_t xmax,
        Double_t ymin,
        Double_t ymax,
        Double_t zmin,
        Double_t zmax,
        Int_t npar);

   TF3J(const char *name,
        ROOT::Math::ParamFunctor f,
        Double_t xmin,
        Double_t xmax,
        Double_t ymin,
        Double_t ymax,
        Double_t zmin,
        Double_t zmax,
        Int_t npar);

   TF3J(const char *name,
        void* fcn,
        Double_t xmin,
        Double_t xmax,
        Double_t ymin,
        Double_t ymax,
        Double_t zmin,
        Double_t zmax,
        Int_t npar,
        char* className);

   ~TF3J();

   /*   virtual void SetParameter(Int_t ipar, Double_t parvalue) {
      std::cout << "Setting parameter " << ipar << " to " << parvalue <<
      std::endl;
      TF3::SetParameter(ipar, parvalue);
      std::cout << "Now " << GetParameter(ipar) << std::endl;
   }*/
   
   void GetRandom3(Double_t&,Double_t&,Double_t&);
   
protected:
   
   double ***fIntegral_cache; ///< Integral caches for each bin in Q2,
                              ///< depol factor and (x, phi, kT).
                              ///< The (x, phi, kT) 3D bin is converted into
                              ///< a 1D bin here.
   double *fIntegral; ///< Temporary pointer to the current bin's integral
   double qs; ///< Q-squared
   int qs_j; ///< Q-squared bin number
   int type_j; ///< Bin combining bin in depol factor and whether the
               ///< fragmentation is favoured or unfavoured.
   int mod_fact, lower;
   double micro_bin_edge;
   double binsize;
   double qs_2;
   
   ClassDef(TF3J, 1)
};

#endif
